package bookstudytest.singleton;

/**
 * @author: Lee
 * @Date: 2018/6/11 11:49
 * @Description: 双重检查锁，
 */
public class LazyDoubleLockDemo {
    private LazyDoubleLockDemo() {
        System.out.println("我开始了老哥！");
    }

    public static volatile LazyDoubleLockDemo lazyDoubleLockDemo = null;
    public static LazyDoubleLockDemo getInstance(){
        if (lazyDoubleLockDemo == null){
            //在使用构造方法生成实例时获得锁，获得锁之后再进行一次判断是否有实例
            //这种方式是减少加锁的范围
            //这种方式在语句转化成计算机指令时，还是会出先线程不安全问题，
            /**
             * 因为，这里会涉及到一个指令重排序问题。instance = new Singleton2()其实可以分为下面的步骤：
             1.申请一块内存空间；
             2.在这块空间里实例化对象；
             3.instance的引用指向这块空间地址；
             指令重排序存在的问题是：
             对于以上步骤，指令重排序很有可能不是按上面123步骤依次执行的。
             比如，先执行1申请一块内存空间，然后执行3步骤，instance的引用去指向刚刚申请的内存空间地址，
             那么，当它再去执行2步骤，判断instance时，由于instance已经指向了某一地址，它就不会再为null了，
             因此，也就不会实例化对象了。这就是所谓的指令重排序安全问题。那么，如何解决这个问题呢？

             我们需要在创建引用变量时加上volatile关键字，因为volatile可以禁止指令重排序
             */
            synchronized (LazyDoubleLockDemo.class){
                if (lazyDoubleLockDemo ==null){
                    lazyDoubleLockDemo = new LazyDoubleLockDemo();
                }
            }
        }
        return lazyDoubleLockDemo;
    }
}
